package com.dd.cloud.user.service.paynotice.channel;

import cn.isuyu.easy.pay.spring.boot.autoconfigure.vos.WxpayCallBackVO;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyV3Result;
import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyResult;
import com.dd.cloud.common.constants.OrderConstants;
import com.dd.cloud.user.entity.order.OrderFlow;
import com.dd.cloud.user.enums.ExceptionEnum;
import com.dd.cloud.user.service.order.IOrderFlowService;
import com.dd.cloud.user.service.order.IOrderPayService;
import com.dd.cloud.user.service.paynotice.NoticeOrderService;
import com.dd.cloud.user.service.paynotice.PayNoticeService;
import com.dd.cloud.user.service.product.IPayParamService;
import com.dd.cloud.common.enums.ZkExceptionEnum;
import com.dd.cloud.common.exception.ZekeException;
import com.zk.pay.constants.CS;
import com.zk.pay.model.MchInfoConfigContext;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.tuple.MutablePair;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;

/**
 * <p>
 * 微信回调service 支付回调/退款回调
 * </p>
 *
 * @author zeke
 * @since 2020-03-20
 */
@Service
@Slf4j
public class WxpayNoticeService implements PayNoticeService {
    @Autowired
    private DataSourceTransactionManager dataSourceTransactionManager;
    @Autowired
    private TransactionDefinition transactionDefinition;
    @Autowired
    private IPayParamService payParamService;
    @Autowired
    private IOrderPayService orderPayService;
    @Autowired
    private IOrderFlowService orderFlowService;
    @Autowired
    private NoticeOrderService noticeOrderService;


    /**
     * 微信支付回调
     *
     * @param request 回调参数
     */
    @Override
    public void payNotify(HttpServletRequest request, MutablePair<String, Object> mutablePair, MchInfoConfigContext mchInfoConfigContext) {
        WxpayCallBackVO vo = new WxpayCallBackVO();
        if (CS.PAY_IF_VERSION.WX_V2.equals(mchInfoConfigContext.getApiVersion())) {
            WxPayOrderNotifyResult notifyRes = (WxPayOrderNotifyResult) mutablePair.getRight();
            BeanUtils.copyProperties(notifyRes, vo);
            vo.setTotalFee(String.valueOf(notifyRes.getTotalFee()));
            vo.setAppId(notifyRes.getAppid());
            handlerWxNotifyData(request, vo);
            return;
        }
        WxPayOrderNotifyV3Result.DecryptNotifyResult notifyV3Res = (WxPayOrderNotifyV3Result.DecryptNotifyResult) mutablePair.getRight();
        vo.setOutTradeNo(notifyV3Res.getOutTradeNo());
        vo.setTotalFee(String.valueOf(notifyV3Res.getAmount().getTotal()));
        handlerWxNotifyData(request, vo);
    }

    /**
     * 处理微信支付回调
     *
     * @param wxpayCallBackVO 回调参数
     */
    public void handlerWxNotifyData(HttpServletRequest request, WxpayCallBackVO wxpayCallBackVO) {
        String outFlowTradeNo = wxpayCallBackVO.getOutTradeNo();
        //获取本项目的订单号
        log.info("获取系统性单号:{}", outFlowTradeNo);
        //手动开启事务
        TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);
        OrderFlow flow;
        try {
            long totalFee = Long.parseLong(wxpayCallBackVO.getTotalFee());
            QueryWrapper<OrderFlow> q = new QueryWrapper<>();
            q.lambda().eq(OrderFlow::getFlowNo, outFlowTradeNo);
            flow = orderFlowService.getOne(q);
            if (flow == null) {
                throw new ZekeException(ExceptionEnum.ORDER_NOT_FOUND);
            }
            //流水已是支付状态, 重复回调, 不处理
            if (flow.getStatus() == OrderConstants.FlowStatus.PAY) {
                return;
            }
            if (totalFee != flow.getTotalFee()) {
                // 金额不符
                throw new ZekeException(ExceptionEnum.INVALID_ORDER_PARAM);
            }
            // 支付成功
            // 修改流水状态
            flow.setStatus(OrderConstants.FlowStatus.PAY);
            // 设置支付时间
            flow.setPayDate(LocalDateTime.now());
            // 设置支付方式
            //flow.setPayMethod(OrderConstants.ZkopOrderPayMethod.weixin.getValue());
            UpdateWrapper<OrderFlow> q2 = new UpdateWrapper<>();
            q2.lambda().eq(OrderFlow::getFlowNo, outFlowTradeNo);
            boolean count = orderFlowService.update(flow, q2);
            if (!count) {
                throw new ZekeException(ExceptionEnum.UPDATE_ORDER_STATUS_ERROR);
            }
            //手动提交事务
            dataSourceTransactionManager.commit(transactionStatus);
        } catch (Exception e) {
            e.printStackTrace();
            //手动回滚事务
            dataSourceTransactionManager.rollback(transactionStatus);
            throw new ZekeException(ZkExceptionEnum.UPDATE_ERROR);
        }
        //汇总主订单
        noticeOrderService.calcMainOrder(request, flow.getOrderNo(), flow.getFlowNo(), OrderConstants.FlowType.PAY);
    }

    /**
     * 微信退款的成功回调
     *
     * @return 返回处理结果
     */
    @Override
    public void refundNotify(HttpServletRequest request, Object params) {
        WxPayRefundNotifyResult.ReqInfo reqInfo = (WxPayRefundNotifyResult.ReqInfo) params;
        handleWxRefundData(request, reqInfo);
    }

    /**
     * 退款回调, 修改流水状态和统计订单金额
     *
     * @param reqInfo
     */
    public void handleWxRefundData(HttpServletRequest request, WxPayRefundNotifyResult.ReqInfo reqInfo) {
        String outFlowTradeNo = reqInfo.getOutRefundNo();
        log.info("商户退款单号" + reqInfo.getOutTradeNo());
        //手动开启事务
        TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);
        OrderFlow flow;
        try {
            long refundFee = reqInfo.getRefundFee();
            QueryWrapper<OrderFlow> q = new QueryWrapper<>();
            q.lambda().eq(OrderFlow::getFlowNo, outFlowTradeNo);
            flow = orderFlowService.getOne(q);
            if (flow == null) {
                throw new ZekeException(ExceptionEnum.ORDER_NOT_FOUND);
            }
            if (refundFee != flow.getTotalFee()) {
                // 金额不符
                throw new ZekeException(ExceptionEnum.INVALID_ORDER_PARAM);
            }
            // 支付成功
            // 修改流水状态
            flow.setStatus(OrderConstants.FlowStatus.PAY);
            // 设置支付时间
            flow.setPayDate(LocalDateTime.now());
            // 设置支付方式
            //flow.setPayMethod(OrderConstants.ZkopOrderPayMethod.weixin.getValue());
            UpdateWrapper<OrderFlow> q2 = new UpdateWrapper<>();
            q2.lambda().eq(OrderFlow::getFlowNo, outFlowTradeNo);
            boolean count = orderFlowService.update(flow, q2);
            if (!count) {
                throw new ZekeException(ExceptionEnum.UPDATE_ORDER_STATUS_ERROR);
            }
            //手动提交事务
            dataSourceTransactionManager.commit(transactionStatus);
        } catch (Exception e) {
            e.printStackTrace();
            //手动回滚事务
            dataSourceTransactionManager.rollback(transactionStatus);
            throw new ZekeException(ZkExceptionEnum.UPDATE_ERROR);
        }
        //汇总主订单
        noticeOrderService.calcMainOrder(request, flow.getOrderNo(), reqInfo.getOutTradeNo(), OrderConstants.FlowType.REFUND);
    }

}
